package com.unknown.dapp.uni.swap.log.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.unknow.first.api.common.CommonPage;
import com.unknown.dapp.uni.swap.log.ISwapNoticeHandler;
import com.unknown.dapp.uni.swap.log.config.SwapTokenConfig;
import com.unknown.dapp.uni.swap.log.dto.ContractConfigDTO;
import com.unknown.dapp.uni.swap.log.dto.ContractLogDTO;
import com.unknown.dapp.uni.swap.log.mapper.TTokenSwapRecord;
import com.unknown.dapp.uni.swap.log.mapper.TTokenSwapRecordMapper;
import com.unknown.dapp.uni.swap.log.service.ITokenSwapRecordService;
import com.unknown.dapp.uni.swap.log.util.ConvertContractValue;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.cloud.mybatisplus.vo.JavaBeanResultMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.StringUtils;
import org.web3j.abi.datatypes.Address;
import org.web3j.utils.Numeric;

/**
 * @author Administrator
 * @description 针对表【t_token_swap_record(NFT转账记录表，根据链的区块来扫描。)】的数据库操作Service实现
 * @createDate 2022-03-18 16:42:49
 */
@Service
@Slf4j
public class TokenSwapRecordServiceImpl extends ServiceImpl<TTokenSwapRecordMapper, TTokenSwapRecord>
    implements ITokenSwapRecordService {

    @Autowired(required = false)
    ISwapNoticeHandler swapNoticeHandler;
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    public CommonPage<TTokenSwapRecord> findListByPage(Integer page, Integer limit, String orderBy,
        QueryWrapper<TTokenSwapRecord> queryWrapper) {

        try (Page<TTokenSwapRecord> pageInfo = getPageInfo(page, limit, orderBy)) {
            List<TTokenSwapRecord> list = baseMapper.selectList(queryWrapper);
            return CommonPage.restPage(list);
        }

    }

    private Page<TTokenSwapRecord> getPageInfo(Integer page, Integer limit, String orderBy) {
        Page<TTokenSwapRecord> pageInfo = null;
        if (StringUtils.isEmpty(orderBy)) {
            pageInfo = PageHelper.startPage(page, limit);
        } else {
            pageInfo = PageHelper.startPage(page, limit, orderBy);
        }
        return pageInfo;
    }

    @Override
    public List<JavaBeanResultMap> countSwapResultByDay(Map<String, Object> params) {
        return this.getBaseMapper().countSwapResultByDay(params);
    }

//    @Transactional(rollbackFor = Exception.class, propagation = Transactional.Propagation.REQUIRED)
    public void processSingleSwapTokenTransferLogs(ContractLogDTO contractLogs, ContractConfigDTO contractConfig) throws Exception {
        TTokenSwapRecord tokenSwapRecord = new TTokenSwapRecord();
        tokenSwapRecord.setContractConfigId(contractConfig.getContractConfigId());
        tokenSwapRecord.setPairAddress(contractConfig.getContractAddress());
        tokenSwapRecord.setTransactionHash(contractLogs.getTransHash());
        tokenSwapRecord.setBlockNumber(contractLogs.getBlockNumber());
        tokenSwapRecord.setBlockTimestamp(contractLogs.getBlockTimestamp());
        tokenSwapRecord.setFromAddress(new Address(contractLogs.getSecondTopic()).toString());
        tokenSwapRecord.setToAddress(new Address(contractLogs.getThirdTopic()).toString());
        tokenSwapRecord.setIndexForBlock(contractLogs.getIndexForBlock());
        tokenSwapRecord.setCreateBy("system");
        SwapTokenConfig swapTokenConfig = JSON.parseObject(contractConfig.getPairConfig(), SwapTokenConfig.class);
        List<String> list = ConvertContractValue.convertDataToValueList(contractLogs.getLogData());
        BigInteger bigAmount0In = Numeric.decodeQuantity(list.get(0));
        BigDecimal amount0In = ConvertContractValue.bigIntegerToBigDecimal(bigAmount0In, swapTokenConfig.getToken0().getDecimals());
        BigInteger bigAmount1In = Numeric.decodeQuantity(list.get(1));
        BigDecimal amount1In = ConvertContractValue.bigIntegerToBigDecimal(bigAmount1In, swapTokenConfig.getToken1().getDecimals());
        BigInteger bigAmount0out = Numeric.decodeQuantity(list.get(2));
        BigDecimal amount0Out = ConvertContractValue.bigIntegerToBigDecimal(bigAmount0out, swapTokenConfig.getToken0().getDecimals());
        BigInteger bigAmount1out = Numeric.decodeQuantity(list.get(3));
        BigDecimal amount1Out = ConvertContractValue.bigIntegerToBigDecimal(bigAmount1out, swapTokenConfig.getToken1().getDecimals());
        if (swapTokenConfig.getToken0().getIsCoinBase()) { // token0时法币的处理
            if (amount0In.compareTo(BigDecimal.ZERO) > 0) {  // token0的值大于零，那么就是买入
                tokenSwapRecord.setBuyOrSale(10);
                tokenSwapRecord.setAmountIn(amount0In);  // 对于路由的出金，对于用户来说就是入金
                tokenSwapRecord.setAmountInSymbol(swapTokenConfig.getToken0().getSymbol());
                tokenSwapRecord.setAmountOut(amount1Out);  // 对于路由的入金，对于用户来出就是出金
                tokenSwapRecord.setAmountOutSymbol(swapTokenConfig.getToken1().getSymbol());
                this.getBaseMapper().insert(tokenSwapRecord);
            }
            if (amount1In.compareTo(BigDecimal.ZERO) > 0) { // token1的值大于零，那么就是卖出
                tokenSwapRecord.setBuyOrSale(20);
                tokenSwapRecord.setAmountIn(amount0Out);
                tokenSwapRecord.setAmountInSymbol(swapTokenConfig.getToken0().getSymbol());
                tokenSwapRecord.setAmountOut(amount1In);
                tokenSwapRecord.setAmountOutSymbol(swapTokenConfig.getToken1().getSymbol());
                this.getBaseMapper().insert(tokenSwapRecord);
            }
        } else if (swapTokenConfig.getToken1().getIsCoinBase()) { // token1时法币的处理
            if (amount0In.compareTo(BigDecimal.ZERO) > 0) { // token0的值大于零，那么就是卖出
                tokenSwapRecord.setBuyOrSale(20);
                tokenSwapRecord.setAmountIn(amount1Out);
                tokenSwapRecord.setAmountInSymbol(swapTokenConfig.getToken1().getSymbol());
                tokenSwapRecord.setAmountOut(amount0In);
                tokenSwapRecord.setAmountOutSymbol(swapTokenConfig.getToken0().getSymbol());
                this.getBaseMapper().insert(tokenSwapRecord);
            }
            if (amount1In.compareTo(BigDecimal.ZERO) > 0) { // token1的值大于零，那么就是买入
                tokenSwapRecord.setBuyOrSale(10);
                tokenSwapRecord.setAmountIn(amount1In);
                tokenSwapRecord.setAmountInSymbol(swapTokenConfig.getToken1().getSymbol());
                tokenSwapRecord.setAmountOut(amount0Out);
                tokenSwapRecord.setAmountOutSymbol(swapTokenConfig.getToken0().getSymbol());
                this.getBaseMapper().insert(tokenSwapRecord);
            }
        }
        if (swapNoticeHandler != null) {
            swapNoticeHandler.handle(tokenSwapRecord);
        }
    }

    @Override
    public void processSwapTokenTransferLogs() {
        List<ContractConfigDTO> contractConfigList = this.getBaseMapper().selectContractConfig();
        for (ContractConfigDTO contractConfig : contractConfigList) {
            if (StrUtil.isEmpty(contractConfig.getPairConfig())) {
                continue;
            }
            try {
                SwapTokenConfig swapTokenConfig = JSON.parseObject(contractConfig.getPairConfig(), SwapTokenConfig.class);
                if (!(swapTokenConfig.getToken0().getIsCoinBase() || swapTokenConfig.getToken1().getIsCoinBase())) {
                    log.error("{}未正确的设置法币（稳定币），请检查！{}", contractConfig.getContractAddress(), contractConfig.getPairConfig());
                    continue;
                }
                if (swapTokenConfig.getToken0().getIsCoinBase() && swapTokenConfig.getToken1().getIsCoinBase()) {
                    log.error("{}未正确的设置法币（稳定币），请检查！{}", contractConfig.getContractAddress(), contractConfig.getPairConfig());
                    continue;
                }
                List<ContractLogDTO> logsList = getBaseMapper().selectSwapTokenTransferLogs(50, contractConfig.getContractAddress());
                for (ContractLogDTO contractLog : logsList) {
                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
                    TransactionStatus status = transactionManager.getTransaction(def);
                    try {
                        this.processSingleSwapTokenTransferLogs(contractLog, contractConfig);
                        transactionManager.commit(status);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        // 回滚事务
                        transactionManager.rollback(status);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }

        }
    }
}




